/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#ifndef MK_SDP_H
#define MK_SDP_H
#include "MkUtil/MkTime.h"

//https://mirrors.nju.edu.cn/rfc/beta/errata/rfc2327.html  SDP: Session Description Protocol

class MkApi CMkSdpAttribute
{
public:
    CMkSdpAttribute(const MkString& Field, const MkString& Value = "");
    CMkSdpAttribute() {}
    ~CMkSdpAttribute() {}
    Uint32 ParseContent(const MkString& Content);
    const MkString& GetField() const { return m_Field; }
    const MkString& GetValue() const { return m_Value; }
    Uint32 ToString(MkString& Content);
private:
    MkString        m_Field;
    MkString        m_Value;
};

class MkApi CMkSdpFmt
{
    //a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters > ]
    //a=fmtp:<playload type> ....
public:
    CMkSdpFmt();
    CMkSdpFmt(Uint32 Payload, const MkString& EncodingName, Uint32 ClockRate, Uint32 EncodingParams = 0);
    ~CMkSdpFmt() {}
    Uint32 ParseContent(const MkString& Content);
    Uint32 GetPayload() const { return m_Payload; }
    const MkString& GetEncodingName() const { return m_EncodingName; }
    Uint32 GetClockRate() const { return m_ClockRate; }
    Uint32 GetEncodingParams() const { return m_EncodingParams; }
    const MkString& GetPps() const { return m_VideoPps; }
    const MkString& GetSps() const { return m_VideoSps; }
    const MkString& GetVps() const { return m_VideoVps; }
    //const Uint32& GetProfileLevelId() const { return m_H264ProfileLevelId; }
    //const Uint32& GetH264PacketMode() const { return m_H264PacketMode; }
    MkMapString& GetFmtp() { return m_MapOtherFmtp; }
    Uint32 ToString(OUT MkString& Content);
    Uint32 ToFmtpString(OUT MkString& Content);
    Uint32 AddFmtp(const MkString& Fmtp);
    void SetBase64Sps(const MkString& Sps);
    void SetBase64Pps(const MkString& Pps);
    void SetBase64Vps(const MkString& Vps);
    void SetSps(const MkString& Sps);
    void SetPps(const MkString& Pps);
    void SetVps(const MkString& Vps);
    void SetPayload(Uint32 Payload) { m_Payload = Payload; }
    void SetEncodingName(const MkString& EncodingName) { m_EncodingName = EncodingName; }
    void SetEncodingParams(Uint32 EncodingParams) { m_EncodingParams = EncodingParams; }
    void SetClockRate(Uint32 ClockRate) { m_ClockRate = ClockRate; }
    void SetH264ProfileLevelId(Uint32 Id) { m_H264ProfileLevelId = Id; }
    void SetH264PacketMode(Uint32 Mode) { m_H264PacketMode = Mode; }
    void SetFmtpNode(const MkString& Key, const MkString& Value) { m_MapOtherFmtp[Key] = Value; }

    void SetH265ProfileSpace(Uint32 ProfileSpace) { m_H265ProfileSpace = ProfileSpace; }
    void SetH265ProfileId(Uint32 ProfileId) { m_H265ProfileId = ProfileId; }
    void SetH265TierFlag(Uint32 TierFlag) { m_H265TierFlag = TierFlag; }
    void SetH265LevelId(Uint32 LevelId) { m_H265LevelId = LevelId; }
    void SetH265InteropConstraints(const MkString& InteropConstraints) { m_H265InteropConstraints = InteropConstraints; }

private:
    Uint32                              m_Payload;
    MkString                            m_EncodingName;
    Uint32                              m_ClockRate;
    Uint32                              m_EncodingParams;
    //sprop-vps=QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ; sprop-sps=QgEBAWAAAAMAAAMAAAMAAAMAlqADwIARB8uNrkkya5Zk; sprop-pps=RAHgdrAmQA==  265
    //or sprop-parameter-sets=Z00AKY2NQDwBE/LCAAAOEAACvyAI,aO44gA==   sps and pps 264
    MkString                            m_VideoBase64Sps;
    MkString                            m_VideoBase64Pps;
    MkString                            m_VideoBase64Vps;
    MkString                            m_VideoSps;
    MkString                            m_VideoPps;
    MkString                            m_VideoVps;
    Uint32                              m_H264ProfileLevelId;  //profile-level-id=15
    Uint32                              m_H264PacketMode;  //packetization-mode
    Uint32                              m_H265ProfileSpace;
    Uint32                              m_H265ProfileId;
    Uint32                              m_H265TierFlag;
    Uint32                              m_H265LevelId;
    MkString                            m_H265InteropConstraints;

    MkMapString	                        m_MapOtherFmtp;
};


class MkApi CMkSdpBandWidth
{
public:
    CMkSdpBandWidth(const MkString& Modifier, const MkString& BandWidth);
    CMkSdpBandWidth() {}
    ~CMkSdpBandWidth() {}
    Uint32 ParseContent(const MkString& Content);
    const MkString& GetModifier() const { return m_Modifier; }
    const MkString& GetBandWidth()const { return m_BandWidth; }
    Uint32 ToString(MkString& Content);
    BOOL Empty() const { return m_Modifier.empty() && m_BandWidth.empty(); }
private:
    MkString        m_Modifier;
    MkString        m_BandWidth;
};

class MkApi CMkSdpConnection
{
    //c=<network type> <address type> <connection address>/[TTL]/[number of address]
public:
    CMkSdpConnection();
    CMkSdpConnection(const MkString& NetType, const MkString&AddrType, const MkString& Addr, Uint8 MulticastTtl = 0, Uint8 MulticastCount = 0);
    ~CMkSdpConnection() {}
    Uint32 ParseContent(const MkString& Content);
    const MkString& GetNetType() const { return m_NetType; }
    const MkString& GetAddrType() const { return m_AddrType; }
    const MkString& GetAddr()const { return m_Addr; }
    Uint8 GetMulticastTtl() { return m_AddrMulticastTtl; }
    Uint8 GetMulticastCount() { return m_AddrMulticastCount; }
    Uint32 ToString(MkString& Content);
    BOOL Empty();
private:
    MkString        m_NetType;
    MkString        m_AddrType;
    MkString        m_Addr;
    Uint8           m_AddrMulticastTtl;
    Uint8           m_AddrMulticastCount;
};

class MkApi CMkSdpMedia
{
    //m=<media> <port>/<number of ports> <transport> <fmt list>
public:
    CMkSdpMedia();
    ~CMkSdpMedia();
    Uint32 ParseContent(const MkString& Content);
    const MkString& GetMediaType() const { return m_MediaType; }
    Uint16 GetPort()const { return m_Port; }
    Uint8 GetNumberOfPort()const { return m_NumberOfPort; }
    const MkString& GetProtocol()const { return m_Protocol; }
    const MkMapString& GetExtend()const { return m_MapExtend; }
    Uint32 GetExtendValue(const MkString& strKey, MkString& strValue) const;
    const MkMap<Uint32, CMkSdpFmt>& GetFmts() const { return m_MapFmt; }
    const MkVector<CMkSdpAttribute>& GetAttributes() const { return m_VecAttri; }
    const MkString& GetControlUri()const { return m_ControlUri; }
    Uint32 GetBandWidth() const;
    const Uint32& GetVideoWidth()const { return m_VideoWidth; }
    const Uint32& GetVideoHeight() const { return m_VideoHeight; }
    const Uint32& GetVideoFrameRate()const { return m_VideoFrameRate; }
    const double& GetPlayStartTime() const { return m_PlayStartTime; }
    const double GetPlayEndTime()  const { return m_PlayEndTime; }
    const CMkTime& GetAbsStartTime()const { return m_AbsStartTime; }
    const CMkTime& GetAbsEndTime() const { return m_AbsEndTime; }
    const MkString& GetMikey()const { return m_Mikey; }
    const CMkSdpConnection& GetSdpConnection() const { return m_Connection; }
    const MkString& GetSubType() const { return m_SubType; }

    Uint32 SetMediaType(const MkString& MediaType);
    Uint32 SetPort(Uint16 Port);
    Uint32 SetNumberOfPort(Uint8 NumberOfPort);
    Uint32 SetProtocol(const MkString& Protocol);
    void SetSubType(const MkString& SubType) { m_SubType = SubType; }
    void SetVideoWidth(Uint32 Width) { m_VideoWidth = Width; }
    void SetVideoHeight(Uint32 Height) { m_VideoHeight = Height; }
    void SetVideoFrameRate(Uint32 FrameRate) { m_VideoFrameRate = FrameRate; }
    void SetConnection(const CMkSdpConnection& Connection) { m_Connection = Connection; }
    void SetBindWidth(const CMkSdpBandWidth& BindWidth) { m_BandWidth = BindWidth; }
    void SetControlUri(const MkString& ControlUri) { m_ControlUri = ControlUri; }
    Uint32 AddExtend(const MkString& Key, const MkString& Value);
    void AddAttr(const CMkSdpAttribute& Attr) { m_VecAttri.push_back(Attr); }
    Uint32 AddFmt(const CMkSdpFmt& pSdpFmt);
    Uint32 AddFmtp(Uint32 Playload, const MkString& Fmtp);
    Uint32 ToString(MkString& Content);
protected:
private:
    Uint32 ParseMediaHeader(const MkString& Header);
    Uint32 ParseAttributeRang(const MkString& RangContent);
    Uint32 ParseAttributeSourceFilter(const MkString& FilterContent);
    Uint32 ParseAttributeMikey(const MkString& MikeyContent);
    Uint32 ParseAttributeVideoSolution(const MkString& SolutionContent);
private:
    MkString                            m_MediaType;        //video audio or other
    Uint16                              m_Port;             //
    Uint8                               m_NumberOfPort;
    MkString                            m_Protocol;
    MkString                            m_SubType;          //from state grid b state grid a
    CMkSdpConnection					m_Connection;       //c
    CMkSdpBandWidth						m_BandWidth;        //b
    MkString							m_SessionDesc;		//i=
    MkMapString			                m_MapEncryptionKey; //k=
    MkMap<Uint32, CMkSdpFmt>            m_MapFmt;           //key payload number keys is fmt list
    MkString                            m_SessionType;      //a=type:broadcast|meeting|moderated|test|H.332|recvonly
    MkString                            m_ControlUri;       //a=control
    BOOL                                m_RtcpWithRtp;      //a = rtcp-mux
    //a=range:npt=<startTime>-<endTime>
    double                              m_PlayStartTime;
    double                              m_PlayEndTime;

    ////a=range:clock=20100929T095038.00Z-20100929T102038.00Z
    CMkTime                             m_AbsStartTime;
    CMkTime                             m_AbsEndTime;

    //a=source-filter: incl IN <protocol type> * <sourcename>  or a=source-filter: incl IN <protocol type> * <sourcename>
    MkString                            m_SourceName;
    Uint8                               m_AddressProtocolType;  //IP4 IP6
    MkString                            m_Mikey;            //a=key-mgmt:mikey %s   srtp use

    ////a=x-dimensions:<width>,<height>
    Uint32                              m_VideoWidth;
    Uint32                              m_VideoHeight;
    Uint32                              m_VideoFrameRate;  //a=framerate: <fps>" or "a=x-framerate: <fps>"

    MkVector<CMkSdpAttribute>           m_VecAttri;         //other attribute
    MkMapString                         m_MapExtend;        // user extend key(except the up keys)=value 
};

class MkApi CMkSdpTime
{
public:
    CMkSdpTime(Uint64 StartTime, Uint64 EndTime, const MkVectorString& RepeatTimes = MkVectorString());
    CMkSdpTime();
    ~CMkSdpTime() {}
    Uint32 ParseContent(const MkString& Content);
    Uint32 ParseRepeatTimes(const MkString& RepeatContent);
    Uint32 AddRepeatTimes(const MkVectorString& RepeatTimes);

    void SetTimes(Uint64 StartTime, Uint64 EndTime) { m_StartTime = StartTime; m_EndTime = EndTime; }
    const Uint64& GetStartTime() const { return m_StartTime; }
    const Uint64& GetEndTime() const { return m_EndTime; }
    const MkVectorString& GetRepeatTimes() const { return m_RepeatTimes; }


    Uint32 ToString(MkString& Content);
    Uint32 RepeatTimesToString(MkString& RepeatContent);
private:
    Uint64                          m_StartTime;
    Uint64                          m_EndTime;
    MkVectorString              m_RepeatTimes;      //r= after t=
};


class MkApi CMkOrigin
{
public:
    //o=<username> <session id> <version> <network type> <address type>  <address>
    CMkOrigin() {}
    CMkOrigin(const MkString& UserName, const MkString& SessionId, const MkString& SessionVersion,
        const MkString& NetType, const MkString& AddrType, const MkString& Addr);
    ~CMkOrigin() {}
    Uint32 ParseContent(const MkString& Content);
    const MkString& GetUserName() const { return m_UserName; }
    const MkString& GetSessionId() const { return m_SessionId; }
    const MkString& GetSessionVersion()const { return m_SessionVersion; }
    const MkString& GetAddrType()const { return m_AddrType; }
    const MkString& GetNetType()const { return m_NetType; }
    const MkString& GetAddr()const { return m_Addr; }
    BOOL Empty();

    Uint32 ToString(MkString& OriginContent);
private:
    MkString        m_UserName;
    MkString        m_SessionId;
    MkString        m_SessionVersion;
    MkString        m_NetType;
    MkString        m_AddrType;
    MkString        m_Addr;
};

class MkApi CMkSdp
{
public:
    CMkSdp();
    ~CMkSdp();
    Uint32 ParseContent(const MkString& SdpContent);

    const MkString& GetVersion()const { return m_Version; }
    const CMkOrigin& GetOrigin()const { return m_Origin; }
    const MkString& GetSessionName()const { return m_SessionName; }
    const MkString& GetSessionDesc() const { return m_SessionDesc; }
    const MkString& GetUri()const { return m_Uri; }
    const MkString& GetEmail() const { return m_Email; }
    const MkString& GetPhoneNumber()const { return m_PhoneNumber; }
    const CMkSdpConnection& GetConnection()const { return m_Connection; }
    const CMkSdpBandWidth& GetBandWidth()const { return m_BandWidth; }
    const CMkSdpTime& GetTime()const { return m_TimeDesc; }
    const MkMapString& GetAdjustment() const { return m_MapTimeZones; }
    const MkMapString& GetEncryptionKey()const { return m_MapEncryptionKey; }
    const MkVector<CMkSdpAttribute>&  GetAttribute()const { return m_VecAttribute; }
    const MkVector<CMkSdpMedia>& GetMedia()const { return m_VecMedia; }

    Uint32 SetVersion(const MkString& Version);
    Uint32 SetOrigin(const CMkOrigin& Origin);
    Uint32 SetSessionName(const MkString& SessionName);
    Uint32 SetSessionDesc(const MkString& SessionDesc);
    Uint32 SetUri(const MkString& Uri);
    Uint32 SetEmail(const MkString& Email);
    Uint32 SetPhoneNumber(const MkString& PhoneNumber);
    Uint32 SetConnection(const CMkSdpConnection& Connection);
    Uint32 SetBandWidth(const CMkSdpBandWidth& BandWidth);
    Uint32 SetTime(const CMkSdpTime& SdpTime);
    Uint32 SetTimeZones(const MkMapString& Zones);
    Uint32 SetEncrytionKey(const MkMapString& Encryption);
    Uint32 SetAttribute(const MkVector<CMkSdpAttribute>& Attributes);
    Uint32 AddAttribute(const CMkSdpAttribute& Attr);
    Uint32 SetMedia(const MkVector<CMkSdpMedia>& Media);
    Uint32 AddMedia(const CMkSdpMedia& Media);

    Uint32 ToString(MkString& SdpContent);
private:
    MkString                        m_Version;          //v=
    CMkOrigin                       m_Origin;           //o=
    MkString                        m_SessionName;      //s=
    MkString                        m_SessionDesc;      //i=
    MkString                        m_Uri;              //u=
    MkString                        m_Email;            //e=
    MkString                        m_PhoneNumber;      //p=
    CMkSdpConnection				m_Connection;       //c=
    CMkSdpBandWidth                 m_BandWidth;        //b=  
    CMkSdpTime                      m_TimeDesc;         //t= 
    MkMapString                     m_MapTimeZones;     //z= z=<adjustment time> <offset> <adjustment time> <offset> .... //key time value offset
    MkMapString                     m_MapEncryptionKey; //k=  more than one
    MkVector<CMkSdpAttribute>       m_VecAttribute;     //a= more than one
    MkVector<CMkSdpMedia>           m_VecMedia;         //m=
};

#endif